package com.abou.mvc.controller;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.context.ApplicationContext;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.servlet.ModelAndView;
import com.abou.manager.exception.ManagerException;

/**
 * The abstract class defining common methods for controllers (like exceptions
 * handling).
 */
public abstract class CommonController {
  
  /**
   * The name for this view
   */
  protected String viewName;
  
  /**
   * The name of the view to go when an exception occurs. Null if this view is
   * the same as the controller's one.
   */
  protected String exPrevViewName;
  
  @Autowired
  protected ApplicationContext applicationContext;
  
  /**
   * Handles exceptions of the passed type, thrown in the controller
   * 
   * @param exception A manager layer exception
   * @return Information on the view to display
   */
  @ExceptionHandler(ManagerException.class)
  public ModelAndView handleException(ManagerException exception) {

    ModelMap model = new ModelMap();
    model.put(ExceptionController.EX_PARAMS_ATT, exception.getParams());
    
    String prevViewName = exPrevViewName;
    
    if (StringUtils.isBlank(prevViewName)) {
      
      prevViewName = viewName;
    }
    
    model.put(ControllerUtils.BACK_ATT, prevViewName
        + ControllerUtils.VIEW_NAME_SUFFIX);
    
    return new ModelAndView("redirect:/" + ExceptionController.VIEW_NAME
        + ControllerUtils.VIEW_NAME_SUFFIX, model);
  }
  
  /**
   * Returns the passed locale date pattern
   * 
   * @param locale The current locale
   * @return A date pattern
   */
  @ModelAttribute("datePattern")
  public String getDatePattern(Locale locale) {

    return ((SimpleDateFormat) getDateFormatter(locale)).toPattern().toLowerCase();
  }
  
  /**
   * Creates a date formatter for the passed locale
   * 
   * @param locale A locale
   * @return A date formatter
   */
  public static DateFormat getDateFormatter(Locale locale) {

    DateFormat dateFormatter =
        DateFormat.getDateInstance(SimpleDateFormat.SHORT, locale);
    dateFormatter.setLenient(false);
    
    return dateFormatter;
  }
  
  /**
   * Inits a new binder for dates
   * 
   * @param binder The current binder
   * @param locale The current locale
   */
  @InitBinder
  public void initBinder(WebDataBinder binder, Locale locale) {

    // creating the date formatter
    DateFormat dateFormat = getDateFormatter(locale);
    
    // registering the date formatter
    binder.registerCustomEditor(Date.class, new CustomDateEditor(
        dateFormat, true));
  }
  
  /**
   * Handles exceptions thrown from the manager layer. If the exception can be
   * converted into a validation error, the binding result object is modified,
   * and the exception is caught. Otherwise, the exception is re-thrown.
   * 
   * @param mngException The manager exception
   * @param result The binding and validation result for the request
   * @param msgKeyPrefix The prefix for the message keys to use for each
   *          validaion error.
   */
  protected static void handleManagerException(ManagerException mngException,
      BindingResult result, String msgKeyPrefix) {

    // // checking if the exception should be treated as validation error
    // if (Arrays.asList(errorCodes).contains(mngException.getCode())) {
    //
    // String msgCode =
    // msgKeyPrefix
    // + ControllerUtils.getMsgKey(mngException.getCode().name());
    // result.addError(new ObjectError(
    // msgCode, new String[] { msgCode }, new Object[0], ""));
    //
    // } else {
    //
    // throw mngException;
    // }
  }
}
